Repository navigation
Conversation
error-code - name the closed set as cta_values on canonicals, allowed_values in text-asset requirements - cover a card's per-card cta, with error.field pointing at the card - carry the set in details.accepted_values, the core/error.json key - error.field examples use sync_creatives request paths: creatives[0].assets.cta.content and creatives[0].assets.cards[2].cta schemas and docs - text-asset-requirements keeps MUST for the refusal and error.field, SHOULD for the accepted_values key; card-asset names the same code - sync_creatives format conformance and error table say the same - Reels table: the buyer ships assets.cta.content, not assets.cta.text - regenerate the compliance error-code snippet training-agent - send details.accepted_values instead of allowed_values Closes adcontextprotocol#8628
image_carousel - allowed_card_media_asset_types declares default ["image"]; a declaration silent on it and on the deprecated alias accepts image cards only - the format description says the parameter narrows image-or-video and defaults to image - min_cards and max_cards only narrow the cards slot; 35 cards are reached by restating the slot with max: 35 responsive_creative and card-asset - pool counts only narrow the matching slot's min and max - card media is image only when the parameter is omitted docs - carousels: card media and card count section with a 35-card example - canonical-formats, formats and sync_creatives: a parameter with a schema default applies it when omitted; count params never widen a slot Closes adcontextprotocol#8629
schemas - media-buy and creative list-creative-formats-request asset_types keep formats that declare every requested type - an asset counts whether required or optional, top level or inside a repeatable_group; the example matches the rule docs - migration guide states the all-of rule and the one-call-per-type union - list_creatives contrasts its any-of filter over creatives creative-agent - the reference list_creative_formats filter applies all-of Closes adcontextprotocol#8630
product - a multi-publisher product without placements[] MUST NOT carry publisher-scoped format_options; with no product-local declaration left, the seller MUST publish placements[] or split the product docs - formats, canonical-formats and media-products state the rule, the identity-based intersection and the unsellable empty case - per-slice grading now describes a product that breaks the rule - the product-level union applies to products that publish placements changeset - one adcontextprotocol patch for adcontextprotocol#8628, adcontextprotocol#8629, adcontextprotocol#8630 and adcontextprotocol#8631 Closes adcontextprotocol#8631
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema paths require human/CODEOWNERS approval.
This PR modifies published protocol source under static/schemas/source/** (8 files, including product.json, error-code.json, image_carousel.json, responsive_creative.json, card-asset.json, and the list-creative-formats requests). These paths are under a hard, path-based approval gate (gated_paths: true), and review_decision is REVIEW_REQUIRED — not APPROVED. Per decision rule row 2, the outcome must be escalate until a human/CODEOWNERS approval lands.
The reviewer confirmed schema↔docs coherence holds across all touched surfaces and found no critical/high findings. One medium finding remains:
- server/src/creative-agent/task-handlers.ts:224 —
asset_typesfilter flips any-of→all-of under apatchchangeset (correctly implemented and tested, but the base migration doc documented OR). This is a changeset-class judgment worth a human eye given it changes published filter semantics.
Escalation reasons
- Touches gated protocol source (
static/schemas/source/**) withreview_decision: REVIEW_REQUIRED— human/CODEOWNERS approval required before merge. - Medium: asset_types filter semantics flip (any-of→all-of) shipped under a patch changeset — warrants confirmation the changeset class matches the wire-behavior change.
Medium findings
- server/src/creative-agent/task-handlers.ts:224 — asset_types filter flips any-of→all-of under a patch changeset
Why human review
- Gated paths touched (static/schemas/source/** — 8 files) and review_decision is REVIEW_REQUIRED, not APPROVED — human/CODEOWNERS approval required (decision rule row 2).
- Medium: server/src/creative-agent/task-handlers.ts:224 — asset_types filter flips any-of→all-of under a patch changeset; changeset-class judgment on a published filter semantics change warrants a human reviewer.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/assets/card-asset.json (modified) matches
static/schemas/source/**; static/schemas/source/core/product.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/requirements/text-asset-requirements.json (modified) matchesstatic/schemas/source/**; static/schemas/source/creative/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/error-code.json (modified) matchesstatic/schemas/source/**; static/schemas/source/formats/canonical/image_carousel.json (modified) matchesstatic/schemas/source/**; static/schemas/source/formats/canonical/responsive_creative.json (modified) matchesstatic/schemas/source/**; static/schemas/source/media-buy/list-creative-formats-request.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'REVIEW_REQUIRED', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
changeset - minor, since list_creative_formats asset_types moves from any-of to all-of
KonstantinMirin
left a comment
There was a problem hiding this comment.
Two notes. The first corrects a premise in my own issue.
-
asset_types(#8630), on the class call ladon raised. My issue said nothing in the schema or inlist_creative_formats.mdxmarked either reading as normative. The schema part holds. The task-page part was wrong, because I only checked the 3.2 page. From 2.5 through 3.1, that page stated any-of twice: the parameter table says "Uses OR logic" (3.1.32, L41), and an "Asset Types Filter Logic" section says "formats matching ANY specified asset type are returned", with a snippet that filters the results for formats needing both (L600-L618). The 3.2 rewrite dropped both. So all-of reverses the rule the task reference documented through 3.1, not only the migration guide.Moving the changeset to
minorkeeps this out of 3.2.x, but it still changes what an unchanged request returns within 3.x, and a minor only adds. An agent built to the 3.1 page returns different formats for the same["image", "text"]request. I'd keep any-of in 3.x, with this PR's counting of optional andrepeatable_groupassets, stated in the schema as plainly as this PR states all-of, and make all-of the 4.0 rule. -
error.fieldforCREATIVE_VALUE_NOT_ALLOWED. The entry's MUST says "the offending value's path within the manifest", but its examples (creatives[0].assets.cta.content) are request paths, which is whatcore/error.jsondefinesfieldas. Oncreate_media_buythe same value sits atpackages[0].creatives[0].assets.cta.content. "the offending value's path in the request" would fit both.
Closes #8628
Closes #8629
Closes #8630
Closes #8631
Problem
An implementer building
sync_creativesvalidation against v3.2.7 found four places where the creative schemas and docs read two ways. The maintainer answered each issue with the intended rule. This PR writes those answers into the schemas and docs. It builds on #8937 (card_image_sizes), #8940 and #8941 (format conformance), which merged just before.Please confirm: schema defaults vs. #8941's omitted-parameter rule
#8941 says an omitted narrowing parameter sets no limit. Under #8629 a silent
allowed_card_media_asset_typesmeans['image']("the parameter states its own default"), so the two texts disagreed. This PR adds one exception wherever #8941's rule is stated:docs/creative/task-reference/sync_creatives.mdxdocs/creative/canonical-formats.mdxdocs/creative/formats.mdxThe exception: a parameter whose canonical schema states a
defaultapplies that default when omitted. The rule as written also contradicted defaults that already exist, such as every canonical's defaultslotsandseller_rendered_stateful_display.clickthrough: "required". Among the canonical defaults, onlyallowed_card_media_asset_typeschanges what a seller may refuse. If you prefer, this can be narrowed to "a parameter that states its own default".Changes
#8628
cta_valuesandCREATIVE_VALUE_NOT_ALLOWEDenums/error-code.json: the code covers a value outside the closed set the targeted option declares (cta_valueson canonical formats,allowed_valuesin text-asset requirements). It turns on the declared set, not the container, so a card's per-cardctais covered.error.details.accepted_values, the canonical key incore/error.json; also sendingallowed_valuesis harmless. TheenumMetadatasuggestion namesaccepted_values.error.fieldexamples are nowcreatives[0].assets.cta.contentandcreatives[0].assets.cards[2].cta. This drops thecreative_manifestsegment from the maintainer's example (creatives[0].creative_manifest.assets.cards[2].cta):sync_creativesitems (core/creative-asset.json) carryassetsdirectly, andcore/error.jsondefinesfieldas a request-payload path.assets[0].valueexample.creatives[0].assets.cta.content.core/requirements/text-asset-requirements.json(allowed_values): MUST reject and seterror.field; SHOULD carry the list inerror.details.accepted_values. This matches the enum, so a seller that sends the oldallowed_valuesstays conformant.core/assets/card-asset.json(cta) names the same code.sync_creatives.mdx: the format-conformance paragraph and the error table useaccepted_valuesand mention the per-cardcta.canonical-formats.mdxReels table: the buyer shipsassets.cta.content, notassets.cta.text.docs/snippets/compliance-error-codes.mdx.CREATIVE_VALUE_NOT_ALLOWEDdetails carryaccepted_valuesinstead ofallowed_values. No storyboard reads the details key.#8629
image_carouselcard media and card countallowed_card_media_asset_typesgains"default": ["image"]. A declaration that omits both it and the deprecatedallowed_card_asset_typesalias accepts image cards only; declare['image', 'video']for mixed-media carousels.mediacan carryimageorvideo, and the parameter narrows that set and defaults to['image'].min_cards/max_cardsonly narrow thecardsslot.max_cards: 35alone still caps at 10; a product that takes 35 cards restates the slot withmax: 35and may also setmax_cards: 35.responsive_creative: pool counts narrow their slot the same way.card-asset.jsonmedia: image only when the parameter is omitted.carousels.mdxgains a "Card media and card count" section with a 35-card example.canonical-formats.mdx(params.slotssection, Pinterest Idea Pin row) says the same.defaultexception above, in three files.#8630
list_creative_formatsasset_typesmedia-buy/andcreative/list-creative-formats-request.json: keep formats that declare every one of the requested types. An asset counts whether it is required or optional, and whether it is at the top level or inside arepeatable_group. The example matches.migration/creatives.mdxstates the all-of rule and that any-of means one call per type, unioned.list_creatives.mdxends its matching paragraph with a contrast to its own any-of filter over creatives, which is unchanged.list_creative_formatsapplies all-of (it applied any-of), and its tool description says so. No storyboard sendslist_creative_formatswithasset_types.#8631 multi-publisher products without
placements[]core/product.jsonformat_options: adopts the suggested wording. Such a product MUST NOT carry publisher-scoped declarations; when no product-local declaration remains, the seller MUST publishplacements[]or split the product by publisher.formats.mdx,canonical-formats.mdxandmedia-products.mdxstate:placements[].Tests
x-added-in-3-3-sweep6/6.mcp-schema-projection36/36 after rebasing onmain(2dc672e): the controller request measures 1_385_258 bytes, under main's 1_387_000 bound, so this PR leaves the bound alone.training-agent-native-in-feed-options.test.ts+creative-agent.test.ts: 139/139.allowed_values.build:compliance --check;lint-error-codesandsdk-response-conformance(14/14);json-schema-validation --filepasses on the changed docs.snippet-validation --filepasses except for the 10 existing Python/JS snippets insync_creatives.mdx, which fail locally only because the SDKs are not installed here. No code snippets were added.Changeset
.changeset/creative-wording-errata-cta-carousel-filters.md,minor.migration/creatives.mdxdocumented OR), so the changeset isminor, like docs(creative): sellers accept creatives that conform to the declared format option #8941. In 3.3 beta pre-mode the version outcome is the same; it only keeps the change out of a 3.2.x patch backport.Out of scope / follow-ups
image_carouseldeclaringcta_values: the maintainer agreed in cta_values and CREATIVE_VALUE_NOT_ALLOWED: details key, closed-set name, per-card cta, and assets.cta.text #8628 and said it would be tracked as a separate schema change. No tracking issue exists yet; one should be opened before this PR closes cta_values and CREATIVE_VALUE_NOT_ALLOWED: details key, closed-set name, per-card cta, and assets.cta.text #8628.docs/creative/implementing-creative-agents.mdxusescards_min/cards_max, which are notimage_carouselparameters.🤖 Generated with Claude Code